package com.google.sky.util;


import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.sky.MoveResolver;

import com.google.sky.domain.MoveResolverMeta;
import org.apache.commons.io.IOUtils;
import org.springframework.util.StringUtils;
import sun.misc.JarFilter;

import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class ImplementationsFinder {


    public static synchronized List<MoveResolverMeta> findImplementations(String location) {
        if (StringUtils.isEmpty(location)) {
            return Lists.newArrayList();
        }
        final File dir = new File(location);
        if (!dir.exists()) {
            return Lists.newArrayList();
        }
        List<String> files =  Lists.newArrayList(dir.list(new JarFilter()));
        List<File> jarFiles = Lists.transform(files, new Function<String, File>() {
            @Override
            public File apply(String input) {
                return new File(dir, input);
            }
        });
        List<MoveResolverMeta> res = Lists.newArrayList();
        for (File jarFile:jarFiles){
            BufferedReader reader = null;
            try {
                MoveResolver resolver = findImplementations(jarFile);
                if (resolver!=null){
                    String name  = jarFile.getName();
                    String nameFile = name.replaceAll("\\.jar$",".name");
                    File nFile = new File(dir, nameFile);
                    if (nFile.exists()){
                        reader = new BufferedReader(new FileReader(nFile));
                        String teamName = reader.readLine();
                        res.add(new MoveResolverMeta(resolver, teamName));
                    }
                }
            } catch (IOException e) {
                IOUtils.closeQuietly(reader);
            }
        }
        return res;
    }

    private static MoveResolver findImplementations(File file) throws IOException {
        if (file.exists()) {
            JarInputStream jarFile = null;
            URLClassLoader ucl = null;
            final URL url;
            url = new URL("jar:file:" + file.getAbsolutePath() + "!/");
            ClassLoader classLoader = ImplementationsFinder.class.getClassLoader();
            ucl = new URLClassLoader(new URL[]{url}, classLoader);
            jarFile = new JarInputStream(new FileInputStream(file));
            JarEntry jarEntry;
            while (true) {
                jarEntry = jarFile.getNextJarEntry();
                if (jarEntry == null)
                    break;
                if (jarEntry.getName().endsWith(".class")) {
                    String classname = jarEntry.getName().replaceAll("/", "\\.");
                    classname = classname.substring(0, classname.length() - 6);
                    if (!classname.contains("$")) {
                        try {
                            final Class<?> myLoadedClass = Class.forName(classname, true, ucl);
                            if (MoveResolver.class.isAssignableFrom(myLoadedClass)) {
                                MoveResolver res = (MoveResolver) myLoadedClass.newInstance();
                                return res;
                            }
                        } catch (final Exception e) {
                        }
                    }
                }
            }
        }
        return null;
    }
}
